package com.sh.rbac.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.rbac.core.common.enums.UserTypeEnum;
import com.sh.rbac.core.common.exception.CustomException;
import com.sh.rbac.core.common.result.ResultCodeEnum;
import com.sh.rbac.core.security.util.SecurityHolderUtils;
import com.sh.rbac.domain.converter.MenuConverter;
import com.sh.rbac.domain.dto.menu.MenuQueryDTO;
import com.sh.rbac.domain.dto.menu.MenuSaveDTO;
import com.sh.rbac.domain.dto.menu.MenuUpdateDTO;
import com.sh.rbac.domain.entity.Menu;
import com.sh.rbac.domain.entity.User;
import com.sh.rbac.domain.vo.menu.MenuNavVO;
import com.sh.rbac.mapper.MenuMapper;
import com.sh.rbac.service.MenuService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lucky
 * @description 针对表【sys_menu(菜单表)】的数据库操作Service实现
 * @createDate 2024-04-04 21:47:19
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu>
        implements MenuService {

    @Override
    public List<MenuNavVO> getMenus() {
        List<Menu> menus;

        if (SecurityHolderUtils.isAdmin()) {
            menus = baseMapper.getMenusByUserId(null);
        } else {
            menus = baseMapper.getMenusByUserId(SecurityHolderUtils.getUserId());
        }

        return formatMenuNav(menus, 0L);
    }

    @Override
    public List<Menu> getList(MenuQueryDTO menuQueryDTO) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotBlank(menuQueryDTO.getMenuName()), Menu::getMenuName, menuQueryDTO.getMenuName());
        wrapper.eq(menuQueryDTO.getStatus() != null, Menu::getStatus, menuQueryDTO.getStatus());
        wrapper.orderByAsc(Menu::getPriority);

        return buildMenuTree(baseMapper.selectList(wrapper));
    }

    @Override
    public Boolean save(MenuSaveDTO menuSaveDTO) {
        Menu menu = MenuConverter.INSTANCE.toEntity(menuSaveDTO);
        return super.save(menu);
    }

    @Override
    public Boolean updateById(MenuUpdateDTO menuUpdateDTO) {
        Menu menu = MenuConverter.INSTANCE.toEntity(menuUpdateDTO);
        return super.updateById(menu);
    }

    @Override
    public Boolean updateStatus(Long id, Integer status) {
        Menu menu = new Menu();
        menu.setId(id);
        menu.setStatus(status);

        return super.updateById(menu);
    }

    @Override
    public Set<String> getAuth() {
        User user = SecurityHolderUtils.getLoginUser();
        Long userId = UserTypeEnum.isAdmin(user.getUsertype()) ? null : user.getId();

        return new HashSet<>(baseMapper.getPermissionByUserId(userId));
    }

    @Override
    public boolean removeById(Serializable id) {
        List<Menu> menus = baseMapper.selectList(new LambdaQueryWrapper<Menu>().eq(Menu::getParentId, id));
        if (!menus.isEmpty()) {
            throw new CustomException(ResultCodeEnum.NODE_HAS_CHILDREN);
        }
        return super.removeById(id);
    }

    @Override
    public boolean removeBatchByIds(Collection<?> list) {
        try {
            list.forEach(id -> super.removeById((Serializable) id));
        } catch (Exception e) {
            return false;
        }
        return super.removeBatchByIds(list);
    }


    /**
     * 格式化菜单导航
     *
     * @param menus    菜单
     * @param parentId 父节点ID
     * @return 菜单导航视图集合
     */
    private List<MenuNavVO> formatMenuNav(List<Menu> menus, Long parentId) {
        return menus.stream().filter(menu -> menu.getParentId().equals(parentId))
                .map(menu -> {
                    MenuNavVO menuNavVO = new MenuNavVO();
                    menuNavVO.setName(StrUtil.upperFirst(menu.getPath()));
                    menuNavVO.setPath(menu.getPath());
                    menuNavVO.setComponent(menu.getComponent());
                    menuNavVO.setRedirect(menu.getRedirect());
                    menuNavVO.setHidden(menu.getVisible() == 1);
                    MenuNavVO.Meta mate = new MenuNavVO.Meta();
                    mate.setTitle(menu.getMenuName());
                    mate.setIcon(menu.getIcon());
                    menuNavVO.setMeta(mate);
                    menuNavVO.setChildren(formatMenuNav(menus, menu.getId()));
                    return menuNavVO;
                }).collect(Collectors.toList());
    }


    /**
     * 构建菜单树
     *
     * @param menuList 菜单集合
     * @return 部门树
     */
    private List<Menu> buildMenuTree(List<Menu> menuList) {
        // 没有部门直接返回
        if (CollectionUtils.isEmpty(menuList)) {
            return new ArrayList<>();
        }

        // 创建Map便于查找
        Map<Long, Menu> menuMap = menuList.stream()
                .collect(Collectors.toMap(Menu::getId, menu -> menu));

        // 关联父子关系并找出根节点
        List<Menu> rootNodes = new ArrayList<>();

        for (Menu menu : menuList) {
            Long parentId = menu.getParentId();
            Menu parent = menuMap.get(parentId);

            if (parent != null) {
                // 有父节点，建立父子关系
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(menu);
            } else {
                // 没有父节点或父节点不在当前列表中，作为根节点
                rootNodes.add(menu);
            }
        }

        return rootNodes;
    }

}




